package org.hs.phd.odi.tracking.performanceevaluation;

import java.awt.Polygon;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import org.hs.phd.common.charting.LineChartDrawer;
import org.hs.phd.common.simpleplayer.ImageSequenceFrame;
import org.hs.phd.common.simpleplayer.PlayerEvent;
import org.hs.phd.common.simpleplayer.PlayerListener;
import org.hs.phd.odi.tracking.tool.performanceevaluation.PerformanceStatsOverlay;
import org.hs.phd.odi.tracking.tracker.TrackerGroup;
import org.hs.phd.odi.tracking.tracker.TrackerGroup.PaintableTracker;

public class TrackingPerformanceEvaluator implements PlayerListener {
	
	private final TrackerGroup trackers;
	private boolean isFirstTime = true;
	private IdentityHashMap<PaintableTracker, TrackingPerformanceStatistics> performanceStatistics;

	protected Map<String, LineChartDrawer> charts;
	private TrackingPerformanceStatistics performanceMetricsListPrototype;
	private final JPanel chartsPane;
	
	
	public TrackingPerformanceEvaluator(final TrackerGroup trackers, final JPanel chartsPane){
		this.trackers = trackers;
		this.chartsPane = chartsPane;
		
		charts = new HashMap<String, LineChartDrawer>();
		
		performanceStatistics = new IdentityHashMap<PaintableTracker, TrackingPerformanceStatistics>();
		
		performanceMetricsListPrototype = new TrackingPerformanceStatistics();
		performanceMetricsListPrototype.addMetric(new PrecisionMetric());
		performanceMetricsListPrototype.addMetric(new SpatialOverlappingPercentageMetric());
		performanceMetricsListPrototype.addMetric(new RecallMetric());
		performanceMetricsListPrototype.addMetric(new TemporalOverlappingPercentageMetric());
		performanceMetricsListPrototype.addMetric(new F1ScoreMetric());
		performanceMetricsListPrototype.addMetric(new CentersDistancePixelsMetric());

		for(PaintableTracker tracker: trackers.getList()){
			performanceStatistics.put(tracker, performanceMetricsListPrototype.getCopy());
		}
		
		SwingUtilities.invokeLater(new Runnable() {
			

			@Override
			public void run() {
				for(TrackingPerformanceMetric metric : performanceMetricsListPrototype.iterator()){
					LineChartDrawer chart = new LineChartDrawer(trackers.getList(), metric.getName(), "Frames", 
							metric.getUnitName(), false, metric.getRangeMin(), metric.getRangeMax());
					charts.put(metric.getName(), chart);
					chartsPane.add(chart.createDemoPanel());
				}
								
			}
		});
		
		
	}

	@Override
	public void playerEventOccurred(PlayerEvent event) {
		
		if(event.getEventType() != PlayerEvent.EventType.VIEWER_REFRESH){
			updatePerformanceMetricsOverlay(event.getPlayer().getCurrentFrame());
			event.getPlayer().refreshViewer();
		}

		if( event instanceof GroundTruthBroadcastEvent ){
			GroundTruthBroadcastEvent gtEvent = (GroundTruthBroadcastEvent) event;
			
			ImageSequenceFrame currentFrame = gtEvent.getPlayer().getCurrentFrame();

			if(isFirstTime){
				isFirstTime  = false;
				trackers.initTrackers(gtEvent.getGroundTruth(), currentFrame);
				updatePerformanceMetricsOverlay(currentFrame);
				event.getPlayer().refreshViewer();
			}else{

				updatePerformanceMetricsOverlay(currentFrame);
				event.getPlayer().refreshViewer();
				
				trackers.updateWithNextFrame(currentFrame);
				event.getPlayer().refreshViewer();
				updatePerformanceStatistics(gtEvent.getGroundTruth(), currentFrame);

				//show the updated values
				updatePerformanceMetricsOverlay(currentFrame);
				
			}

			event.getPlayer().refreshViewer();
		}

		
	}

	private void updatePerformanceStatistics(Polygon groundTruth, ImageSequenceFrame currentFrame) {
		
		final Map<String, List<Double>> chartsData = new HashMap<String, List<Double>>();
		for(TrackingPerformanceMetric metric : performanceMetricsListPrototype.iterator()){
			List<Double> singleChartData = new ArrayList<Double>();
			chartsData.put(metric.getName(), singleChartData);
		}
		
		for(PaintableTracker tracker: trackers.getList()){
			TrackingPerformanceStatistics statistics = performanceStatistics.get(tracker);
			statistics.update(currentFrame, groundTruth,  tracker.tracker.getCurrentTrackWindow().getAsPolygon());
			
			for(TrackingPerformanceMetric metric : statistics.iterator()){
				//chartsData.get(metric.getName()).add((double)metric.getAverageValue());
				chartsData.get(metric.getName()).add((double)metric.getLastValue());
			}
		}

		
		SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				for(TrackingPerformanceMetric metric : performanceMetricsListPrototype.iterator()){
					charts.get(metric.getName()).addData(chartsData.get(metric.getName()));
				}
			}
		});
	
	}


	private void updatePerformanceMetricsOverlay(ImageSequenceFrame input) {
		input.addOverlay(this, 0, new PerformanceStatsOverlay(performanceStatistics));
	}

}
